function apply(o, c, defaults) {
    if (defaults) {
        apply(o, defaults);
    }
    if (o && c && typeof c === 'object') {
        for (var p in c) {
            o[p] = c[p];
        }
    }
    return o;
};

/*
 * for bson/mongo:
 * sudo apt-get install build-essential
 * npm install mongodb
 */

/**
 * Module dependencies.
 */
var http = require('http');
var url = require('url');
var qs = require('querystring');
var cluster = require('cluster');
var tPAXX = require('./tPAXX');

var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/tpaxx');

var PORT = +process.env.PORT || 3001;

if (cluster.isMaster) {
    cluster.fork();// first worker
    cluster.fork();// second worker
    cluster.on('disconnect', function(worker) {
        console.error('disconnect!');
        cluster.fork();
    });

} else {
    var domain = require('domain');
    var server = http.createServer(function(req, res) {
        var d = domain.create();
        d.on('error', function(er) {
            console.error('error', er.stack);

            // Note: we're in dangerous territory!
            // By definition, something unexpected occurred,
            // which we probably didn't want.
            // Anything can happen now!  Be very careful!

            try {
                // make sure we close down within 30 seconds
                var killtimer = setTimeout(function() {
                    process.exit(1);
                }, 30000);
                // But don't keep the process open just for that!
                killtimer.unref();

                // stop taking new requests.
                server.close();

                // Let the master know we're dead.  This will trigger a
                // 'disconnect' in the cluster master, and then it will fork
                // a new worker.
                cluster.worker.disconnect();

                // try to send an error to the request that triggered the problem
                res.statusCode = 500;
                res.setHeader('content-type', 'text/plain');
                res.end(JSON.stringify({
                    success: false,
                    message: er.message,
                    stack: er.stack
                }));
                //res.end('Oops, there was a problem!\n\n'+er.message);
            } catch (er2) {
                // oh well, not much we can do at this point.
                console.error('Error sending 500!', er2.stack);
            }
        });

        // Because req and res were created before this domain existed,
        // we need to explicitly add them.
        // See the explanation of implicit vs explicit binding below.
        d.add(req);
        d.add(res);

        // Now run the handler function in the domain.
        d.run(function() {
            handleRequest(req, res);
        });
    });
	server.listen(PORT, function() {
        console.log('server listening on port ' + PORT);
    });
}

var regex = new RegExp('(([^:]+)/([^/]+)):([^/]+)(.*)');

function handleRequest(request, res) {
    if (request.method === 'POST' || request.method === 'GET') {
		var buffer = "";

		request.on("data", function(chunk) {
			buffer += chunk;
		});

		request.on("end", function() {
			var json = qs.parse(buffer);
            var REQ = {};
            if (typeof json.data === 'undefined') {
                for (var k in json) {
                    if (json.hasOwnProperty(k)) {
                        if (json[k].length === 0) {
                            REQ = JSON.parse(k);
                            break;
                        }
                    }
                }
            } else {
                var REQ = JSON.parse(json.data);
            }
            var r = url.parse(request.url, true);

            // rewrite path for singleparametrized modules 
            // (/masterdata/type:proximity/list to /masterdata/type/list ?type=proximity)
            var pathname = r.pathname;
            var matches = r.pathname.match(regex);
            if (matches) {
                pathname = matches[1] + matches[5];
                r.query[matches[3]] = matches[4];
            }

			apply(REQ, r.query);
			var instance = new tPAXX({
				db: db,
				path: pathname,
				request: REQ,
				_request: request,
                _parsedUrl: r,
				_response:res
			});
			
			instance.onReady(function(data) {
				res.writeHead(200, {'Content-Type': 'application/json'});
				res.end(JSON.stringify(data));
			});

			instance.execute();
		});
	} else
	{
		res.writeHead(500);
		res.end('internal server error');
	}
}